import bundleManager from '@ohos.bundle.bundleManager';
import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';
import Logger from './Logger';
import common from '@ohos.app.ability.common';

/**
 * 系统权限常量
 */
export class PermissionConstants {
  /**
   * 允许使用Internet网络
   */
  static readonly INTERNET: Permissions = 'ohos.permission.INTERNET';

  /**
   * 允许应用读取日历信息:ohos.permission.READ_CALENDAR
   */
  static readonly READ_CALENDAR: Permissions = 'ohos.permission.READ_CALENDAR';

  /**
   * 允许应用读取联系人数据
   */
  static readonly READ_CONTACTS: Permissions = 'ohos.permission.READ_CONTACTS';

  /**
   * 允许应用使用麦克风
   */
  static readonly MICROPHONE: Permissions = 'ohos.permission.MICROPHONE';

  /**
   * 允许应用在后台运行时获取设备位置信息
   */
  static readonly LOCATION_IN_BACKGROUND: Permissions = 'ohos.permission.LOCATION_IN_BACKGROUND';

  /**
   * 允许应用获取设备模糊位置信息。
   * 申请条件：仅供使用API version 9及API version 9以上版本的SDK开发的应用申请
   */
  static readonly APPROXIMATELY_LOCATION: Permissions = 'ohos.permission.APPROXIMATELY_LOCATION';

  /**
   * 允许应用获取设备位置信息。
   * 申请条件：
   * 使用API version 9以下版本的SDK开发的应用，可以直接申请此权限。
   * 使用API version 9及API version 9以上版本的SDK开发的应用，需要先申请权限ohos.permission.APPROXIMATELY_LOCATION，才可申请此权限
   */
  static readonly LOCATION: Permissions = 'ohos.permission.LOCATION';

  /**
   * 允许应用使用相机拍摄照片和录制视频
   */
  static readonly CAMERA: Permissions = 'ohos.permission.CAMERA';

  /**
   * 允许读取用户公共目录的文档
   */
  static readonly READ_DOCUMENT: Permissions = 'ohos.permission.READ_DOCUMENT';

  /**
   * 允许修改用户公共目录的文档
   */
  static readonly WRITE_DOCUMENT: Permissions = 'ohos.permission.WRITE_DOCUMENT';

  /**
   * 允许读取用户公共目录的图片或视频文件
   */
  static readonly READ_IMAGE_VIDEO: Permissions = 'ohos.permission.READ_IMAGEVIDEO';

  /**
   * 允许修改用户公共目录的图片或视频文件
   */
  static readonly WRITE_IMAGE_VIDEO: Permissions = 'ohos.permission.WRITE_IMAGEVIDEO';

  /**
   * 允许读取用户公共目录的音频文件
   */
  static readonly READ_AUDIO: Permissions = 'ohos.permission.READ_AUDIO';

  /**
   * 允许修改用户公共目录的音频文件
   */
  static readonly WRITE_AUDIO: Permissions = 'ohos.permission.WRITE_AUDIO';

  /**
   * 允许应用读取用户的健康数据
   */
  static readonly READ_HEALTH_DATA: Permissions = 'ohos.permission.READ_HEALTH_DATA';

  /**
   * 允许应用读取用户外部存储中的媒体文件信息
   */
  static readonly READ_MEDIA: Permissions = 'ohos.permission.READ_MEDIA';

  /**
   * 允许应用读写用户外部存储中的媒体文件信息
   */
  static readonly WRITE_MEDIA: Permissions = 'ohos.permission.WRITE_MEDIA';
}

/**
 * 授权验证
 * @param permission 权限
 * @returns 验证结果
 */
export async function checkAccessToken(permission: Permissions): Promise<abilityAccessCtrl.GrantStatus> {
  // 验证授权结果，默认为验证失败
  let grantStatus: abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED;

  if (!permission) return grantStatus;

  let atManager = abilityAccessCtrl.createAtManager();

  // 获取应用程序的accessTokenID
  let tokenId: number;
  try {
    // 获取当前应用信息
    let bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);
    let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;
    //ATM提供的应用权限校验功能是基于统一管理的TokenID（Token identity）。TokenID是每个应用的身份标识，ATM通过应用的TokenID来管理应用的权限。
    tokenId = appInfo.accessTokenId;
  } catch (err) {
    Logger.error('PermissionUtil', `getBundleInfoForSelf failed, code is ${err.code}, message is ${err.message}`);
  }

  // 校验应用是否被授予权限
  try {
    // GrantStatus: PERMISSION_DENIED = -1 未授权，PERMISSION_GRANTED = 0 已授权
    grantStatus = await atManager.checkAccessToken(tokenId, permission);
  } catch (err) {
    Logger.error('PermissionUtil', `checkAccessToken failed, code is ${err.code}, message is ${err.message}`);
  }

  return grantStatus;
}

/**
 * 验证是否已授权
 * @param permissions
 * @returns 是否已授权
 */
export async function checkPermissions(permission: Permissions): Promise<boolean> {
  if (!permission) return false;
  let grantStatus: abilityAccessCtrl.GrantStatus = await checkAccessToken(permission);
  // 是否已经授权
  return grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
}

/**
 * 向用户申请权限
 * @param context 当前 UIAbility 上下文对象
 * @param permission 要申请的系统权限
 * @returns 是否授权成功
 */
export async function requestPermissionFromUser(context: common.Context, permission: Permissions): Promise<boolean> {
  try {
    if (!context || !permission) return false;

    let permissions = [permission];
    let atManager = abilityAccessCtrl.createAtManager();
    let result = await atManager.requestPermissionsFromUser(context, permissions);
    if (result?.authResults?.length > 0) {
      return result.authResults[0] === 0; //0-表示用户授权，可以继续访问目标操作
    }
    return false;
  } catch (err) {
    Logger.error('PermissionUtil', `requestPermissionsFromUser failed, code is ${err.code}, message is ${err.message}`);
    return false;
  }
}

/**
 * 向用户申请权限
 * @param context 当前 UIAbility 上下文对象
 * @param permission 要申请的系统权限
 * @returns 是否授权成功
 */
export function requestPermissionsFromUser(context: common.Context, permissions: Array<Permissions>) {
  try {
    let atManager = abilityAccessCtrl.createAtManager();
    return atManager.requestPermissionsFromUser(context, permissions);
  } catch (err) {
    Logger.error('PermissionUtil', `requestPermissionsFromUser failed, code is ${err.code}, message is ${err.message}`);
    return Promise.reject(err);
  }
}

/**
 * 处理授权结果:
 * 调用requestPermissionsFromUser()方法后，应用程序将等待用户授权的结果。如果用户拒绝授权，则需要提示用户必须授权才能访问当前页面的功能，并引导用户到系统设置中打开相应的权限。
 * @param context 当前 UIAbility 上下文对象
 * @returns Promise<void>
 */
export async function openPermissionsInSystemSettings(context: common.UIAbilityContext): Promise<void> {
  // 获取当前应用信息
  let bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);
  let wantInfo = {
    action: 'action.settings.app.info',
    parameters: {
      settingsParamBundleName: bundleInfo.name // 打开指定应用的详情页面
    }
  }
  // 启动新的Ability（Promise形式）
  return context.startAbility(wantInfo)
}